﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Lookstone.Utility
{
	/// <summary>
	/// Adds generic handling of all Enum types for conversion to and from a friendly string
	/// </summary>
	/// <example>
	/// public enum MyEnumType
	/// {
	///		[Description("My Sample Item")]
	///		SampleItem,
	///		[Description("My Sample Item #2")]
	///		SampleItem2
	///	}
	/// </example>
	public static class EnumTool
	{
		/// <summary>
		/// Retrieves the friendly name string of an enumerated type value
		/// </summary>
		/// <typeparam name="T">Type to convert from</typeparam>
		/// <param name="value">Enumerated value of type</param>
		/// <returns>String containing the friendly name (if available)</returns>
		public static string ToFriendlyString<T>(this T value) where T: struct
		{
			if (!typeof(T).IsEnum)
				throw new ArgumentException("Only valid with enumerated types");

			// Check to see if there's a description attribute on the enum value.
			FieldInfo fieldInfo = typeof(T).GetField(value.ToString());
			DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);

			// If there is a description attribute, use that
			if (attributes.Length > 0)
				return attributes[0].Description;

			// Otherwise just use the built-in string conversion
			return value.ToString();
		}

		/// <summary>
		/// Parses an enumerated value either from the friendly name (if available) or from the string value
		/// </summary>
		/// <typeparam name="T">Type of Enum to use to parse</typeparam>
		/// <param name="stringValue">Value to attempt to parse from</param>
		/// <param name="enumParseOnly">Denotes whether parsing the type will use default parsing functionality or description-based</param>
		/// <returns></returns>
		public static T ParseEnum<T>(this string stringValue, bool enumParseOnly = false) where T: struct
		{
			if (!typeof(T).IsEnum)
				throw new ArgumentException("Only valid with enumerated types");

			if (enumParseOnly)
				return (T)Enum.Parse(typeof(T), stringValue);

			foreach (T enumValue in Enum.GetValues(typeof(T)))
			{
				if (string.Compare(enumValue.ToFriendlyString(), stringValue) == 0)
					return enumValue;
			}

			throw new ArgumentException("The string is not valid for the Enum " + typeof(T).ToString());
		}

		/// <summary>
		/// Retrieves an Array of TypedListItem (of the enum type T)
		/// </summary>
		/// <typeparam name="T">Enum type to retrieve TypedListItems for</typeparam>
		/// <returns>Array of TypedListItem (of T)</returns>
		public static KeyValue<T>[] GetKeyValueItems<T>() where T: struct
		{
			if (!typeof(T).IsEnum)
				throw new ArgumentException("Only valid with enumerated types");

			List<KeyValue<T>> items = new List<KeyValue<T>>();

			KeyValue<T> item = new KeyValue<T>();

			foreach (T enumValue in Enum.GetValues(typeof(T)))
				items.Add(new KeyValue<T>(enumValue, enumValue.ToFriendlyString()));

			return items.ToArray();
		}
	}
}
